package Modelo;
import java.io.*;
import java.util.*;
public class Terreno extends Observable {
        
        private Integer dimensionX;
        
        private Integer dimensionY;

        private Object [][] bloques;
        
        private Planeta planeta;

		private Posicion puertaEntrada;
		
		private Posicion puertaSalida;
        
		public Terreno(String path,Planeta planeta){
        	this.planeta=planeta;
        	reconocimientoDeDimension();
        	this.bloques = new Object[dimensionX][dimensionY];
        	
        	try{                    
        		this.cargaTerreno(path);
        	}catch(FileNotFoundException e){}    
        	ActualizarObservadores();

        }
        
        public Terreno (int dimensionX,int dimensionY,Object[][] bloques,
				Posicion puertaEntrada,Posicion puertaSalida){
        	this.dimensionX=dimensionX;
        	this.dimensionY=dimensionY;
        	this.bloques=bloques;
        	this.puertaEntrada=puertaEntrada;
        	this.puertaSalida=puertaSalida;
        	ActualizarObservadores();

        }
        
        public void setPlaneta(Planeta planeta) {
			this.planeta = planeta;
		}
		
        /**
        Este metodo privado recibe un parametro que permite identificar que
        tipo de bloque construir y devolver. Como es un metodo privado que
        solo se maneja internamente, por lo tanto se prevee que no recibira
        parametros incorrectos, o sea que recibira alguno de los caracteres
        considerados en el switch.
        */
        public Bloque nuevoBloque(Constantes.TIPOS_DE_BLOQUE c, Posicion posicion){
                Bloque bloqueAdevolver = null;
            	int posicionX;
            	int posicionY;
                switch(c){              
                        case TIERRA: bloqueAdevolver = new Tierra(posicion,this.planeta);
                        break;

                        case HIELO: bloqueAdevolver = new Hielo(posicion,this.planeta);
                        break;

                        case FUEGO: bloqueAdevolver = new Fuego(posicion,this.planeta);
                        break;

                        case AGUJERO_NEGRO: bloqueAdevolver = new AgujeroNegro(posicion,this.planeta);
                        break;

                        case BLOQUE_VACIO: bloqueAdevolver = new BloqueVacio(posicion,this.planeta);
                        break;
                        
                        case PUERTA_ENTRADA:
                         	posicionX = posicion.getPosicionX();
                        	posicionY = posicion.getPosicionY();
                        	Posicion posicionPuertaEntrada = new Posicion (posicionX,posicionY);
                        	this.puertaEntrada = posicionPuertaEntrada;
                        	bloqueAdevolver = new PuertaEntrada(posicionPuertaEntrada,this.planeta);                        
                        break;
                        
                        case PUERTA_SALIDA:
                        	posicionX = posicion.getPosicionX();
                        	posicionY = posicion.getPosicionY();
                        	Posicion posicionPuertaSalida = new Posicion (posicionX,posicionY);
                        	this.puertaSalida = posicionPuertaSalida;
                        	bloqueAdevolver = new PuertaSalida(posicionPuertaSalida,this.planeta);
                        break;
                        
                        case ROCA: bloqueAdevolver = new Roca(posicion,this.planeta);
                        break;

                }
                return bloqueAdevolver;
        }
        
        public Bloque nuevoBloqueTunel(Posicion posicion, Boolean haciaDerecha){        	
        	Bloque bloqueAdevolver = new Tunel(posicion,this.planeta,haciaDerecha);        
        	return bloqueAdevolver;
        }
        
        public void reconocimientoDeDimension(){
        	File archivo = null;
        	FileReader fr = null;
        	String dimension = null;
    		String linea = new String();
        	try {
        		archivo = new File ("Niveles/dimension.txt");
        		fr = new FileReader (archivo);
        		BufferedReader br = new BufferedReader(fr);
        		while((linea=br.readLine())!=null){
        			if (linea!=null)
        				dimension=linea;
        		}
        	}        	
        	catch(IOException e){
        		System.out.println(e);
        	}finally{
        		try{                    
        			if( fr != null){   
        				fr.close();   
        			}                  
        		}catch (IOException e){
        			System.out.println(e);
        		}
        	}
        	StringTokenizer tokens = new StringTokenizer(dimension,"*");
        	this.dimensionX = Integer.parseInt(tokens.nextToken());
        	this.dimensionY = Integer.parseInt(tokens.nextToken());
        }
        
        private void cargaTerreno(String path)throws FileNotFoundException{
        	File inputFile = new File(path); 
            FileReader in = new FileReader(inputFile);                              
            int c; 
            try{
            	c = in.read();
            	for (int j=0; j<dimensionY; j++){
            		for (int i=0; i<dimensionX; i++){
                		if(c != -1 ){
                			if (c!=10){     
                				Constantes.TIPOS_DE_BLOQUE bloque = 
                					ConvertidorDeCaracteres.Convertir((char)c);
                				bloques[i][j] = nuevoBloque(bloque, new Posicion(i,j));
                			}
                    		c = in.read();
                		}
                	}
            	}
            	in.close();
            } catch (IOException e) {                       
                    System.out.println("No se pudo cerrar el archivo");
            }      
        }
        
        public Bloque queBloqueHay(int posicionX, int posicionY){
			return (Bloque) bloques[posicionX][posicionY];
        	
        }
        
        public void eliminarBloque (Posicion posicion){
        	this.bloques[posicion.getPosicionX()][posicion.getPosicionY()]        	                                      
        	=nuevoBloque(Constantes.TIPOS_DE_BLOQUE.BLOQUE_VACIO,posicion);
        	ActualizarObservadores();
        }
        
        public synchronized void construirBloque (Constantes.TIPOS_DE_BLOQUE tipo, Posicion posicion){
        	this.bloques[posicion.getPosicionX()][posicion.getPosicionY()]
        	=nuevoBloque(tipo,posicion);
        	ActualizarObservadores();
        }
        
        public void construirTunel (Posicion posicion, boolean haciaDerecha){

    		int posicionX = posicion.getPosicionX();
    		int posicionY = posicion.getPosicionY();
    		Posicion posicionEnPlaneta = new Posicion(posicionX,posicionY);
        	this.bloques[posicionX][posicionY]
        	=new Tunel(posicionEnPlaneta,this.planeta,haciaDerecha);
        	ActualizarObservadores();
        }
        
        public List <Pooglin> getPooglins(){
        	return this.planeta.getPooglins();
        }
        
        public String toString(){        	
        	String terreno = new String();
        	for (int j=0; j<dimensionY; j++){
        		for (int i=0; i<dimensionX; i++){
					boolean yaImprimio=false;
                	Iterator<Pooglin> miIterador = getPooglins().iterator();
        	       	while (miIterador.hasNext()){
                		Pooglin pooglin = (Pooglin) miIterador.next();
        	        	Posicion posicion = pooglin.getPosicion();	
        				if (i==posicion.getPosicionX() && j==posicion.getPosicionY()
        						&& !yaImprimio){
        					System.out.print('$');
        					yaImprimio=true;
        				}        				
                	}
        			if ((Bloque) bloques[i][j]!=null&&!yaImprimio)
        				System.out.print(((Bloque) bloques[i][j]).toString());
        		}
        		System.out.println();
        	}
        	return terreno;
        }

		public Posicion getPuertaSalida() {
			return puertaSalida;
		}
		
		public Posicion getPuertaEntrada() {
			return puertaEntrada;
		} 
		
		public Object getBloques() {
			return this.bloques;
		} 
		
		public Integer getDimensionX(){
			return this.dimensionX;
		}
		
		public Integer getDimensionY(){
			return this.dimensionY;
		}
		
		public Planeta getPlaneta(){
			return this.planeta;
		}
		
		public void ActualizarObservadores()
		{
			setChanged();
			notifyObservers();		
		}
}
